/**
 * 
 */
package uy.org.softtech.cssuite.helpers;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import javax.xml.bind.annotation.XmlTransient;

import org.joda.time.Interval;
import org.joda.time.format.PeriodFormat;
import org.joda.time.format.PeriodFormatter;

/**
 * Clase con métodos utilitarios para trabajar con fechas y horas.
 *
 * @author fabian.lobo
 */
@XmlTransient
public class HelperFechaHora {

	private static final SimpleDateFormat FORMATO_CORTO = new SimpleDateFormat("dd-MMM-yyyy");
	private static final SimpleDateFormat FORMATO_LARGO = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss zzz");
	
	/**
	 * Retorna la fecha y hora actual.
	 * 
	 * @author fabian.lobo
	 */
	public static synchronized Timestamp horaActual(){
		return new Timestamp(System.currentTimeMillis());
	}
	
	/**
	 * Retorna la fecha actual.
	 * 
	 * @author fabian.lobo
	 */
	public static synchronized Date fechaActual(){
		return Calendar.getInstance().getTime();
	}
	
	/**
	 * Retorna la fecha actual con formato corto.
	 *
	 * @return una representacion de la fecha con el siguiente formato - 'MM/dd/yyyy'.
	 * @author fabian.lobo
	 */
	public static synchronized String fechaCorta(){
		return FORMATO_CORTO.format(fechaActual());
	}
	
	/**
	 * Retorna la fecha actual con formato largo.
	 *
	 * @return una representacion de la fecha con el siguiente formato - 'MM/dd/yyyy HH:mm:ss zzz'.
	 * @author fabian.lobo
	 */
	public static synchronized String fechaLarga(){
		return FORMATO_LARGO.format(fechaActual());
	}
	
	/**
	 * Retorna la fecha dada con formato corto.
	 *
	 * @param fecha - La fecha a convertir.
	 * @return una representacion de la fecha con el siguiente formato - 'MM/dd/yyyy' - o un texto vacío si la fecha es nula.
	 * @author fabian.lobo
	 */
	public static synchronized String fechaCorta(Date fecha){
		return fecha != null ? FORMATO_CORTO.format(fecha) : "";
	}
	
	/**
	 * Retorna la fecha dada con formato largo.
	 *
	 * @param fecha - La fecha a convertir.
	 * @return una representacion de la fecha con el siguiente formato - 'MM/dd/yyyy HH:mm:ss zzz' - o un texto vacío si la fecha es nula.
	 * @author fabian.lobo
	 */
	public static synchronized String fechaLarga(Date date){
		return date != null ? FORMATO_LARGO.format(date) : "";
	}

	/**
	 * Retorna el primer dia del mes actual (con hora 00:00:00.000).
	 * @author fabian.lobo
	 */
	public static synchronized Date primerDiaDelMes() {
		Calendar current = Calendar.getInstance();
		current.set(Calendar.DATE, current.getActualMinimum(Calendar.DATE));
		current.set(Calendar.HOUR, 0);
		current.set(Calendar.MINUTE, 0);
		current.set(Calendar.SECOND, 0);
		current.set(Calendar.MILLISECOND, 000);
		current.set(Calendar.AM_PM, Calendar.AM);
		return current.getTime();
	}
	
	/**
	 * Retorna el primer dia del mes de la fecha dada (con hora 00:00:00.000).
	 * 
	 * @param fecha - La fecha de donde calcular.
	 * @author fabian.lobo
	 */
	public static synchronized Date primerDiaDelMes(Date date) {
		Calendar temp = Calendar.getInstance();
		temp.setTime(date);
		
		Calendar current = Calendar.getInstance();
		current.set(Calendar.YEAR, temp.get(Calendar.YEAR));
		current.set(Calendar.MONTH, temp.get(Calendar.MONTH));
		current.set(Calendar.DATE, temp.getActualMinimum(Calendar.DATE));
		current.set(Calendar.HOUR, 0);
		current.set(Calendar.MINUTE, 0);
		current.set(Calendar.SECOND, 0);
		current.set(Calendar.MILLISECOND, 000);
		current.set(Calendar.AM_PM, Calendar.AM);		
		return current.getTime();
	}
	
	/**
	 *  Retorna el primer dia del mes del mes y año dados (con hora 00:00:00.000).
	 * 
	 * @param anio - Año del cual calcular
	 * @param mes - Mes del cual calcular
	 * @author fabian.lobo
	 */
	public static synchronized Date primerDiaDelMes(int anio, int mes) {
		Calendar current = Calendar.getInstance();
		current.set(Calendar.YEAR, anio);
		current.set(Calendar.MONTH, mes - 1);
		current.set(Calendar.DATE, current.getActualMinimum(Calendar.DATE));
		current.set(Calendar.HOUR, 0);
		current.set(Calendar.MINUTE, 0);
		current.set(Calendar.SECOND, 0);
		current.set(Calendar.MILLISECOND, 000);
		current.set(Calendar.AM_PM, Calendar.AM);		
		return current.getTime();
	}
	
	/**
	 * Retorna el ultimo dia del mes actual (con hora 23:59:59.999).
	 * @author fabian.lobo
	 */
	public static synchronized Date ultimoDiaDelMes() {
		Calendar current = Calendar.getInstance();
		current.set(Calendar.DATE, current.getActualMaximum(Calendar.DATE));
		current.set(Calendar.HOUR, 23);
		current.set(Calendar.MINUTE, 59);
		current.set(Calendar.SECOND, 59);
		current.set(Calendar.MILLISECOND, 999);
		current.set(Calendar.AM_PM, Calendar.AM);
		return current.getTime();
	}
	
	/**
	 * Retorna el ultimo dia del mes de la fecha dada (con hora 23:59:59.999).
	 * 
	 * @param fecha - La fecha de donde calcular.
	 * @author fabian.lobo
	 */
	public static synchronized Date ultimoDiaDelMes(Date date) {
		Calendar temp = Calendar.getInstance();
		temp.setTime(date);
		
		Calendar current = Calendar.getInstance();
		current.set(Calendar.YEAR, temp.get(Calendar.YEAR));
		current.set(Calendar.MONTH, temp.get(Calendar.MONTH));
		current.set(Calendar.DATE, temp.getActualMaximum(Calendar.DATE));
		current.set(Calendar.HOUR, 23);
		current.set(Calendar.MINUTE, 59);
		current.set(Calendar.SECOND, 59);
		current.set(Calendar.MILLISECOND, 999);
		current.set(Calendar.AM_PM, Calendar.AM);		
		return current.getTime();
	}
	
	/**
	 * Retorna el ultimo dia del mes anterior al actual (con hora 23:59:59.999).
	 * @author fabian.lobo
	 */
	public static synchronized Date ultimoDiaMesPasado() {
		Calendar current = Calendar.getInstance();
		current.add(Calendar.MONTH, -1);
		current.set(Calendar.DATE, current.getActualMaximum(Calendar.DATE));
		current.set(Calendar.HOUR, 23);
		current.set(Calendar.MINUTE, 59);
		current.set(Calendar.SECOND, 59);
		current.set(Calendar.MILLISECOND, 999);
		current.set(Calendar.AM_PM, Calendar.AM);
		return current.getTime();
	}
	
	/**
	 * Lleva las horas, minutos, segundos y milisegundos a cero para la fecha dada.
	 * 
	 * @param fecha - La fecha para cambiar las horas
	 * @return la fecha dada con el tiempo modificado (con hora 00:00:00.000).
	 * @author fabian.lobo
	 */
	public static synchronized Date reseteaHoras(Date fecha) {
		Calendar temp = Calendar.getInstance();
		temp.setTime(fecha);
		
		Calendar current = Calendar.getInstance();
		current.set(Calendar.YEAR, temp.get(Calendar.YEAR));
		current.set(Calendar.MONTH, temp.get(Calendar.MONTH));
		current.set(Calendar.DATE, temp.get(Calendar.DATE));
		current.set(Calendar.HOUR, 0);
		current.set(Calendar.MINUTE, 0);
		current.set(Calendar.SECOND, 0);
		current.set(Calendar.MILLISECOND, 0);
		current.set(Calendar.AM_PM, Calendar.AM);		
		return current.getTime();
	}

	/**
	 * Retorna la duración en forma de texto entre inicio y fin
	 * 
	 * @param inicio - Tiempo de inicio del período
	 * @param fin - Tiempo de fin del período
	 * @param locale - Localización para el idioma del texto
	 * @author fabian.lobo
	 */
	public static synchronized String duracion(long inicio, long fin, Locale locale) {
		Interval intervalo = new Interval(inicio, fin);
		PeriodFormatter format = PeriodFormat.wordBased(locale);
		StringBuffer buffer = new StringBuffer();
		format.printTo(buffer, intervalo.toPeriod());
		return buffer.toString();
	}
}
